package waal.pc.frontend;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import java.net.DatagramPacket;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;

import javax.swing.JFrame;
import javax.swing.JTabbedPane;

import waal.pc.backend.Reader;
import waal.pc.backend.Sender;

import waal.pc.backend.hub.Hub;
import waal.pc.backend.hub.HubEvent;
import waal.pc.backend.hub.HubEventListener;
import waal.pc.backend.writer.CSVwriter;
import waal.pc.frontend.config.WaalConfig;
import waal.pc.frontend.tiles.Tile;
import waal.pc.frontend.tiles.UpdateableTile;
import waal.pc.frontend.timer.KeepAlive;
import waal.pc.frontend.timer.TileUpdater;


public class Surface extends WindowAdapter {

	private JFrame f;
	private JTabbedPane tabPane;
	private LogTab debugTab;
	private Reader reader;
	private Sender sender;
	private Map<Integer, Hub> hubs;
	private int hubCount = 1;
	//private List<TileInterface> usedTiles;
	private List<UpdateableTile> updateableTiles;
	private Container contentPane;
	private TileTab tileTab;
	//private NewTileDialog dialog;
	private Timer timer;
	public static int tile_x = 200;
	public static int tile_y = 200;
	private Set<HubEventListener> hubEventListener;
	private CSVwriter csv;
	private WaalActions waalActions;
	private WaalConfig wc;
	private ProcessTab processTab;
	
		
	public Surface(Reader reader, Sender sender) {
		this.reader = reader;
		this.sender = sender;
		this.hubs = new HashMap<Integer,Hub>();
		this.updateableTiles = new LinkedList<UpdateableTile>();
		this.hubEventListener = new HashSet<HubEventListener>();
		this.timer = new Timer();
		this.waalActions = new WaalActions(this);
		this.wc = new WaalConfig(this);
		this.f = new JFrame("Wal watching");
		this.f.setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE );
		this.f.setSize( 1000, 700 );
		this.contentPane = this.f.getContentPane();
		this.f.add(new ToolBar(this).getToolBar(),BorderLayout.PAGE_START);
		this.tabPane = new JTabbedPane();
		this.tileTab = new TileTab(this);
		this.processTab = new ProcessTab(this);
		this.debugTab = new LogTab();
		this.contentPane.add(this.tabPane);
		this.tabPane.add("Dash",this.tileTab.getPane());
		this.tabPane.add("Config", this.wc.getPanel());
		this.tabPane.add("Process", this.processTab.getPanel());
		this.tabPane.add("Debug",this.debugTab.getTabPane());
		//this.dialog = new NewTileDialog(this.f, this);
		this.f.setVisible( true );
		this.f.addWindowListener(this);
		this.csv = new CSVwriter(this);
		this.timer.schedule(new TileUpdater(this), 1000, 90);
		this.timer.schedule(new ScanForHubs(this), 100, 60000);
		this.timer.schedule(new KeepAlive(this), 1000, 2000);
		//this.f.pack();
		
	}
		

	public void addHub(Hub hub) {
		//if(!this.hubs.containsKey(hub.getNumber())) {
			this.hubs.put(hub.getNumber(), hub);
		//}
		
	}
	
	public void removeHub(Hub hub) {
		if(this.hubs.containsKey(hub.getNumber())) {
			this.hubs.get(hub.getNumber()).exitHub();
			this.hubs.remove(hub.getNumber());
		}				
	}
	
	public void SendHubConfig(Hub hub, DatagramPacket packet) {
		this.sender.sendConfig(hub, packet);
		}
	
	public void sendRequesMaster(Hub hub, boolean master) {
		this.sender.sendRequesMaster(hub, master);
	}
	
	public void sendRequesShortConfig(Hub hub) {
		this.sender.sendRequesShortConfig(hub);
	}
	
	public void sendRequesLongConfig(Hub hub) {
		this.sender.sendRequesLongConfig(hub);
	}
	
	public void sendStop(Hub hub) {
		this.sender.sendStop(hub);
	}
	
	public void sendKeepAlive() {
		Hub hub;
		for(Iterator<Hub> i = this.hubs.values().iterator(); i.hasNext(); ) {
			hub = i.next();
			if(hub.isMaster()) {
				this.sender.sendKeepAlive(hub);
			}
		}
	}
	
	public void startMeasuring(Hub hub) {
		this.reader.addHub(hub);
		this.csv.startHub(hub);
		this.sender.sendStart(hub);
	}
	
	public void stopMeasuring(Hub hub) {
		this.reader.removeHub(hub);	
	}
		
	public boolean addHubToReader(Hub hub) {
		if(this.reader.addHub(hub)){
			this.fireHubEvent(new HubEvent(4,hub));
			return true;
		} else {
			return false;
		}
	}
	
	public Hub getHub(int number) {
		return this.hubs.get(number);
	}
	
	public Collection<Hub> getHubs() {
		return this.hubs.values();
	}
	
	public void scanForHubs() {
		ScanForHubs s = new ScanForHubs(this);
		new Thread(s).start();
	}
	
	public int getNextHubNumber() {
		return this.hubCount++;
	}
	
	public WaalActions getWaalActions() {
		return this.waalActions;
	}
	
	public void addTile(Tile tile, int position) {
		this.tileTab.addTile(tile, position);
	}
	
	public void addTileToUpdater(UpdateableTile tile) {
		this.updateableTiles.add(tile);		
	}
	
	
	public void removeTileFromUpdater(UpdateableTile tile) {
		this.updateableTiles.remove(tile);	
	}
	
	public void updateTiles() {
		Iterator<UpdateableTile> i = this.updateableTiles.iterator();
		while(i.hasNext()) {
			i.next().updateTile();
		}
	}
	/*
	public void showNewTileDialog(int number) {
		this.dialog.showForTile(number);
	}*/
		
	public boolean addHubEventListener(HubEventListener listener) {
		return this.hubEventListener.add(listener);
	}
	
	public boolean removeHubEventListener(HubEventListener listener) {
		return this.hubEventListener.remove(listener);
	}
	
	public void fireHubEvent(HubEvent e) {
		//Log.addToDebug(2, "Surface", "fireHubEvent", "Fire Hub Event " + e.getEvent() + " for Hub: " + e.getHub().getNumber() + " Event: " + e.getEventText());
		for(Iterator<HubEventListener> i = this.hubEventListener.iterator(); i.hasNext(); ) {
			i.next().actionHubEvent(e);
		}
	}
	
	@Override
	public void windowClosing( WindowEvent e) {
		Set<Integer> exitHubs = new HashSet<Integer>(this.hubs.keySet());
		int number; 
		for(Iterator<Integer> ih = exitHubs.iterator(); ih.hasNext(); ) {
			number = ih.next();
			this.hubs.get(number).exitHub();
			this.hubs.remove(number);
		}
		System.exit(0);
		
	}
}
